//
//  ALDefine.swift
//  ALCore
//
//  Created by IdeaBank on 2023/12/18.
//

import Foundation
//import Then
import SnapKit

import UIKit
//----Int---//
public extension Int {

    /// 转为布尔值
    var boolValue: Bool {
        return self != 0
    }

    /// 是否为偶数
    var isEven: Bool {
        return (self & 1 == 0)
    }

    /// 是否为奇数
    var isOdd: Bool {
        return (self & 1 != 0)
    }

    /// 转为Double
    var doubleValue: Double {
        return toDouble()
    }

    /// 转为Float
    var floatValue: Float {
        return toFloat()
    }

    /// 转为CGFloat
    var cgFloatValue: CGFloat {
        return toCGFloat()
    }

    /// 转为String
    var stringValue: String {
        return toString()
    }

    /// 转为UInt
    var UIntValue: UInt {
        return toUInt()
    }

    /// 转为Double
    func toDouble() -> Double {
        return Double(self)
    }

    /// 转为Float
    func toFloat() -> Float {
        return Float(self)
    }

    /// 转为CGFloat
    func toCGFloat() -> CGFloat {
        return CGFloat(self)
    }

    /// 转为String
    func toString() -> String {
        return String(self)
    }

    /// 转为UInt
    func toUInt() -> UInt {
        return UInt(self)
    }

    /// 转为Int32
    func toInt32() -> Int32 {
        return Int32(self)
    }
}

//----Double---//
public extension Double {

    /// 将浮点数转Int
    var intValue: Int {
        return toInt()
    }

    /// 将浮点数转CGFloat
    var cgFloatValue: CGFloat {
        return toCGFloat()
    }

    /// 将浮点数转String
    var stringValue: String {
        return toString()
    }

    /// 将浮点数转NSNumber
    var numberValue: NSNumber {
        return toNumber()
    }

    /// 将浮点数转Int
    func toInt() -> Int {
        return Int(self)
    }

    /// 将浮点数转CGFloat
    func toCGFloat() -> CGFloat {
        return CGFloat(self)
    }

    /// 将浮点数转String
    func toString() -> String {
        return String(describing: self)
    }

    /// 将浮点数转NSNumber
    func toNumber() -> NSNumber {
        return NSNumber(value: self)
    }

    /// 返回乘以scale后浮点数
    func multiplied(_ scale: Double) -> Double {
        return (self * scale)
    }
}

public extension Double {

    /// 将浮点数四舍五入，自定义小数点后保留的位数
    /// 同上方法，在大量循环计算时性能相对更优，精度低于`stringValueRound()`
    func roundValue(reserved digits: Int = 2, formatted: Bool = true) -> String {
        let divisor = pow(10.0, Double(digits))
        let numberValue = floor(self * divisor + 0.5) / divisor
        if formatted { return String(format: "%.*lf", digits, numberValue) }
        return String(describing: numberValue)
    }

    /// 将浮点数四舍五入，自定义小数点后保留的位数
    ///
    /// 使用round()函数或NumberFormatter类，格式化的浮点数会出现误差，
    /// 因为这并非真正的四舍五入，而是遵循的"银行家算法"，大致规则：
    /// `四舍六入五考虑，五后非零就进一，五后为零看奇偶，五前为偶应舍去，五前为奇要进一`
    /// 为此该函数内部使用了对浮点型计算更加精准的NSDecimalNumber类来避免精度误差。
    /// 但使用NSDecimalNumber并非没有此问题，不过保留两位小数时是精准的，如果保留多位结果还会按"银行家算法"计算，例如
    ///
    ///     let w = 0.655665
    ///     let m = 0.565655
    ///     // 保留两位小数时：w = 0.66    m = 0.57
    ///     // 保留五位小数时：w = 0.65567 m = 0.56565 (期望m应该为0.56566)
    ///
    /// 默认规则:
    ///
    ///     let x: Double = 0.135       // x = 0.14
    ///     let y: Double = 0.145       // y = 0.15
    ///
    /// - Parameters:
    ///   - digits: 保留多少位小数，默认保留两位小数
    ///
    ///         let a = 0.14562
    ///         digits = 3          // a = 0.146
    ///         digits = 4          // a = 0.1456
    ///
    ///   - formatted: 是否格式化，默认YES
    ///
    ///         let b = 0.15
    ///         digits = 3
    ///         formatted = true    // b = 0.150
    ///         formatted = false   // b = 0.15
    ///
    /// - Returns: 指定保留位数的浮点数字符串(四舍五入)
    func roundedValue(reserved digits: Int = 2, formatted: Bool = true) -> String {
        let number = NSDecimalNumber(value: self)._dwnRound(digits)
        guard formatted else {
            return number.stringValue
        }
        return String(format: "%.*lf", digits, number.doubleValue)
    }

    /// 将浮点数百分比化，自定义保留位数
    ///
    /// 默认规则:
    ///
    ///     let x: Double = 0.10125       // x = 10.14%
    ///     let y: Double = 0.10155       // y = 10.15%
    ///
    /// - Parameters:
    ///   - digits: 保留多少位小数，默认保留两位小数
    ///
    ///         let a = 0.145625
    ///         digits = 3          // a = 14.563%
    ///         digits = 4          // a = 14.5625%
    ///
    ///   - formatted: 是否格式化，默认YES
    ///
    ///         let b = 0.152
    ///         digits = 3
    ///         formatted = true    // b = 15.200%
    ///         formatted = false   // b = 15.2%
    ///
    /// - Returns: 转为百分比形式的字符串(四舍五入)
    func percentageValue(reserved digits: Int = 2, formatted: Bool = true) -> String {
        let nup = NSDecimalNumber(value: self)._dwnRound(digits + 2)
        let newp = nup.multiplying(byPowerOf10: 2)
        if formatted { return String(format: "%.*lf%%", digits, newp.doubleValue) }
        return newp.stringValue + "%"
    }

    /// 获取浮点数小数部分(四舍五入)
    ///
    ///     let x: Double = 10.135       // x = 0.14
    ///     let y: Double = 10.145       // y = 0.15
    ///
    /// - Parameters:
    ///   - digits: 保留多少位小数，默认保留两位小数
    ///
    ///         let a = 10.13505
    ///         digits = 4          // a = 0.1351
    ///         digits = 5          // a = 0.13505
    ///
    ///   - formatted: 是否格式化，默认YES
    ///
    ///         let b = 10.13
    ///         digits = 4
    ///         formatted = true    // a = 0.1300
    ///         formatted = false   // a = 0.13
    ///
    /// - Returns: 只有小数部分的字符串(四舍五入)
    func onlyDecimalsValue(reserved digits: Int = 2, formatted: Bool = true) -> String {
        let value = self - Double(Int(self))
        let number = NSDecimalNumber(value: value)._dwnRound(digits)
        if formatted { return String(format: "%.*lf", digits, number.doubleValue) }
        return number.stringValue
    }

    /// 指定保留位数的浮点数字符串(注：若小数点后保留两位就直接取后两位的小数，不四舍五入)
    ///
    /// 默认规则:
    ///
    ///     let x: Double = 12.135       // x = 12.13
    ///     let y: Double = 12.145       // y = 12.14
    ///
    /// - Parameters:
    ///   - digits: 保留多少位小数，默认保留两位小数
    ///
    ///         let a = 0.14562
    ///         digits = 3          // a = 0.145
    ///         digits = 4          // a = 0.1456
    ///
    ///   - formatted: 是否格式化，默认YES
    ///
    ///         let b = 0.15
    ///         digits = 3
    ///         formatted = true    // b = 0.150
    ///         formatted = false   // b = 0.15
    ///
    /// - Returns: 指定保留位数的浮点数字符串(不四舍五入)
    func unestimatedValue(reserved digits: Int = 2, formatted: Bool = true) -> String {
        let divisor = pow(10.0, Double(digits))
        let numberValue = Double(Int(self * divisor)) / divisor
        if formatted { return String(format: "%.*lf", digits, numberValue) }
        return String(describing: self)
    }

    /// 将浮点数转成万亿字符串
    ///
    ///     let x: Double = 125601          // x = 12.56万
    ///     let y: Double = 1256010101      // y = 12.56亿
    ///     let z: Double = 12560101015001  // z = 12.56万亿
    ///
    /// - Parameters:
    ///   - digits: 保留多少位小数，默认保留两位小数
    ///   - formatted: 是否格式化，默认YES
    ///
    ///         let a = 12000
    ///         digits = 3
    ///         formatted = true    // a = 1.200万
    ///         formatted = false   // a = 1.2万
    ///
    /// - Returns: 万亿/亿/万为后缀的字符串
    func trillionSuffixValue(reserved digits: Int = 2, formatted: Bool = true) -> String {
        let value = fabs(self)
        let tuples: (index: Int, unit: String)
        if value < 10000 { tuples = (0, "") }
        else if value < 100000000 { tuples = (4, "万") }
        else if value < 1000000000000 { tuples = (8, "亿") }
        else { tuples = (12, "万亿") }
        let numberValue = self / pow(10.0, Double(tuples.index))
        return numberValue.roundedValue(reserved: digits, formatted: formatted) + tuples.unit
    }

    /// 将浮点数转成货币书写形式
    ///
    ///     let x: Double = 1209001
    ///     // digits set 2, x = 1,209,001.00
    ///     // formatted set NO, x = 1,209,001
    ///     // signed set YES, x = $1,209,001
    ///
    /// - Parameters:
    ///   - digits: 保留多少位小数，默认保留两位小数
    ///   - formatted: 是否格式化，默认YES
    ///   - signed: 是否显示货币符号，默认NO
    ///
    /// - Returns: 返回货币书写形式 (即每三位使用逗号分隔)
    func currencyValue(reserved digits: Int = 2, formatted: Bool = true, signed: Bool = false) -> String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.maximumFractionDigits = digits
        formatter.minimumFractionDigits = formatted ? digits : 0
        if signed { return formatter.string(from: NSNumber(value: self))! }
        formatter.locale = Locale(identifier: "zh_CN")
        var result = formatter.string(from: NSNumber(value: self))!
        result.remove(at: result.startIndex)
        return result
    }

    /// 将浮点数转成人民币大写朗读形式
    ///
    ///     let x: Double = 12092         // x = 壹万贰仟零玖拾贰圆整
    ///     let y: Double = 12092.5212    // y = 壹万贰仟零玖拾贰圆伍角贰分
    ///     let z: Double = 2152092.056   // z = 贰佰壹拾伍万贰仟零玖拾贰圆零角伍分
    ///
    /// - Returns: 返回人民币大写朗读形式，保留到角分
    func rmbCapitalizedValue() -> String {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "zh_CN")
        formatter.numberStyle = .spellOut
        formatter.maximumFractionDigits = 2
        guard let value = formatter.string(from: NSNumber(value: self)) else { return "" }

        func mapC(_ c: Character) -> String {
            switch c {
            case "千": return "仟"
            case "百": return "佰"
            case "十": return "拾"
            case "九": return "玖"
            case "八": return "捌"
            case "七": return "柒"
            case "六": return "陆"
            case "五": return "伍"
            case "四": return "肆"
            case "三": return "叁"
            case "二": return "贰"
            case "一": return "壹"
            case "〇": return "零"
            case "点": return "圆"
            default: return String(c)
            }
        }

        if let range = value.range(of: "点") {
            let lower = value[...range.lowerBound].map({ mapC($0) }).joined()
            let upper = value[range.upperBound..<value.endIndex]
            let part = lower + mapC(upper[upper.startIndex]) + "角"
            guard upper.count > 1 else { return part }
            let char = upper[upper.index(after: upper.startIndex)]
            return part + mapC(char) + "分"
        } else {
            return value.map({ mapC($0) }).joined() + "圆整"
        }
    }

    enum MachiningMode {
        case plain, rounded, unestimated, percentage, onlyDecimals, trillionSuffix, currency, capitalizedRmb
    }

    /// 归类以上方法的便捷调用
    func stringValue(_ mode: MachiningMode = .plain, reserved digits: Int = 2, formatted: Bool = true) -> String {
        switch mode {
        case .plain:
            return roundValue(reserved: digits, formatted: formatted)
        case .rounded:
            return roundedValue(reserved: digits, formatted: formatted)
        case .unestimated:
            return unestimatedValue(reserved: digits, formatted: formatted)
        case .percentage:
            return percentageValue(reserved: digits, formatted: formatted)
        case .onlyDecimals:
            return onlyDecimalsValue(reserved: digits, formatted: formatted)
        case .trillionSuffix:
            return trillionSuffixValue(reserved: digits, formatted: formatted)
        case .capitalizedRmb:
            return rmbCapitalizedValue()
        case .currency:
            return currencyValue(reserved: digits, formatted: formatted, signed: true)
        }
    }
}

//----NSDecimalNumber---//
private extension NSDecimalNumber {

    func _dwnRound(_ places: Int) -> NSDecimalNumber {
        let handler = NSDecimalNumberHandler(roundingMode: .plain, scale: Int16(places), raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
        return self.rounding(accordingToBehavior: handler)
    }
}

//----CGFloat---//
public extension CGFloat {

    /// 获取CGFloat的绝对值
    var absValue: CGFloat {
        return Swift.abs(self)
    }

    /// 将CGFloat转Int
    var intValue: Int {
        return toInt()
    }

    /// 将CGFloat转Double
    var doubleValue: Double {
        return toDouble()
    }

    /// 将CGFloat转String
    var stringValue: String {
        return toString()
    }

    /// 将CGFloat转Int
    func toInt() -> Int {
        return Int(self)
    }

    /// 将CGFloat转Double
    func toDouble() -> Double {
        return Double(self)
    }

    /// 将CGFloat转String
    func toString() -> String {
        return String(describing: self)
    }

    /// 返回CGFloat的倍数
    func scaled(_ scale: CGFloat) -> CGFloat {
        return self * scale
    }

    /// 将角度转弧度
    func degreesToRadians() -> CGFloat {
        return (.pi * self) / 180.0
    }

    /// 将弧度转角度
    func radiansToDegrees() -> CGFloat {
        return (180.0 * self) / .pi
    }

    #if os(iOS)

    /// 将CGFloat转像素点
    func toPixel() -> CGFloat {
        return scaled(UIScreen.main.scale)
    }

    /// 将像素点转换成CGFloat
    func fromPixel() -> CGFloat {
        return self / UIScreen.main.scale
    }

    /// 像素取整类型
    enum FlatType { case ceiled, floored, rounded }

    /// 基于指定的倍数，对CGFloat进行像素取整(默认向上取整)
    func flatted(scale factor: CGFloat = UIScreen.main.scale, type: FlatType = .ceiled) -> CGFloat {
        let value = (self == .leastNonzeroMagnitude || self == .leastNormalMagnitude) ? 0 : self
        let scale = factor > 0 ? factor : UIScreen.main.scale
        switch type {
        case .ceiled:
            return ceil(value * scale) / scale
        case .floored:
            return floor(value * scale) / scale
        case .rounded:
            return Double(value * scale).rounded() / scale
        }
    }

    #endif
}

public extension CGPoint {

    /// 获取圆上任意点坐标
    ///
    /// - Parameters:
    ///   - center: 圆心点坐标
    ///   - radius: 圆的半径
    ///   - radian: 该点所对应的弧度 (顺时针方向，水平第一象限开始)
    ///
    /// - Returns: 该点对应的坐标
    static func pointOnCircle(center: CGPoint, radius: CGFloat, radian: CGFloat) -> CGPoint {
        var result = CGPoint.zero
        let rad = radian + .pi / 2
        if rad < .pi / 2 {
            result.x = center.x + radius * sin(radian)
            result.y = center.y - radius * cos(radian)
        } else if rad < .pi {
            result.x = center.x + radius * sin(.pi - radian)
            result.y = center.y + radius * cos(.pi - radian)
        } else if rad < (.pi + .pi / 2) {
            result.x = center.x - radius * cos((.pi + .pi / 2) - radian)
            result.y = center.y + radius * sin((.pi + .pi / 2) - radian)
        } else {
            result.x = center.x - radius * sin(.pi * 2 - radian)
            result.y = center.y - radius * cos(.pi * 2 - radian)
        }
        return result
    }

    /// 返回两个点之间的距离
    static func distance(_ from: CGPoint, _ to: CGPoint) -> CGFloat {
        return sqrt(pow(to.x - from.x, 2) + pow(to.y - from.y, 2))
    }

    /// 返回两个点之间的中点
    static func center(_ p1: CGPoint, _ p2: CGPoint) -> CGPoint {
        let px = fmax(p1.x, p2.x) + fmin(p1.x, p2.x)
        let py = fmax(p1.y, p2.y) + fmin(p1.y, p2.y)
        return CGPoint(x: px * 0.5, y: py * 0.5)
    }

    /// 判断当前点是否在圆形内 (center: 圆心 radius: 半径)
    func within(center: CGPoint, radius: CGFloat) -> Bool {
        let dx = fabs(Double(x - center.x))
        let dy = fabs(Double(y - center.y))
        return hypot(dx, dy) <= Double(radius)
    }

    /// 将CGPoint放大指定的倍数
    func scaled(_ scale: CGFloat) -> CGPoint {
        return CGPoint(x: x * scale, y: y * scale)
    }

    /// 将CGPoint向上取整
    func ceiled() -> CGPoint {
        return CGPoint(x: ceil(x), y: ceil(y))
    }

    /// 将CGPoint向下取整
    func floored() -> CGPoint {
        return CGPoint(x: floor(x), y: floor(y))
    }

    /// 将CGPoint四舍五入
    func rounded() -> CGPoint {
        return CGPoint(x: round(x), y: round(y))
    }
}

//----CGSize---//
public extension CGSize {

    /// 返回最大的有限CGSize
    static var greatestFiniteMagnitude: CGSize {
        return CGSize(width: CGFloat.greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
    }

    /// 将CGSize放大指定的倍数
    func scaled(_ scale: CGFloat) -> CGSize {
        return CGSize(width: width * scale, height: height * scale)
    }

    /// 将CGSize向上取整
    func ceiled() -> CGSize {
        return CGSize(width: ceil(width), height: ceil(height))
    }

    /// 将CGSize向下取整
    func floored() -> CGSize {
        return CGSize(width: floor(width), height: floor(height))
    }

    /// 将CGSize四舍五入
    func rounded() -> CGSize {
        return CGSize(width: round(width), height: round(height))
    }

    /// 判断CGSize是否存在infinite
    var isInfinite: Bool {
        return width.isInfinite || height.isInfinite
    }

    /// 判断CGSize是否存在NaN
    var isNaN: Bool {
        return width.isNaN || height.isNaN
    }

    /// 判断CGSize是否为空(宽或高小于等于0)
    var isEmpty: Bool {
        return width <= 0 || height <= 0
    }

    /// 判断CGSize是否有效(不包含零值、不带无穷大的值、不带非法数字）
    var isValid: Bool {
        return !isEmpty && !isNaN && !isInfinite
    }
}

//----CGRect---//
public extension CGRect {

    /// 使用宽高初始化CGRect
    init(w: CGFloat, h: CGFloat) {
        self.init(origin: .zero, size: CGSize(width: w, height: h))
    }

    /// 将CGRect放大指定的倍数
    func scaled(_ scale: CGFloat) -> CGRect {
        return CGRect(x: origin.x * scale, y: origin.y * scale,
                      width: size.width * scale, height: size.height * scale)
    }

    /// 将CGRect向上取整
    func ceiled() -> CGRect {
        return CGRect(x: ceil(origin.x), y: ceil(origin.y),
                      width: ceil(size.width), height: ceil(size.height))
    }

    /// 将CGRect向下取整
    func floored() -> CGRect {
        return CGRect(x: floor(origin.x), y: floor(origin.y),
                      width: floor(size.width), height: floor(size.height))
    }

    /// 将CGRect四舍五入
    func rounded() -> CGRect {
        return CGRect(x: round(origin.x), y: round(origin.y),
                      width: round(size.width), height: round(size.height))
    }

    /// 获取矩形中心点最大半径
    func maxRadius() -> CGFloat {
        let center = CGPoint(x: self.width / 2, y: self.height / 2)
        return sqrt(pow(center.x, 2) + pow(center.y, 2))
    }
}

//----UIEdgeInsets---//
public extension UIEdgeInsets {

    /// 获取NSUIEdgeInsets在水平方向上的值
    var horizontal: CGFloat {
        return self.left + self.right
    }

    /// 获取NSUIEdgeInsets在垂直方向上的值
    var vertical: CGFloat {
        return self.top + self.bottom
    }

    /// 返回反转后的NSUIEdgeInsets
    var invert: UIEdgeInsets {
        return UIEdgeInsets(top: -self.top, left: -self.left, bottom: -self.bottom, right: -self.right)
    }

    /// 使用相同的值返回NSUIEdgeInsets
    static func make(same value: CGFloat) -> UIEdgeInsets {
        return UIEdgeInsets(top: value, left: value, bottom: value, right: value)
    }

    /// 设置top值返回NSUIEdgeInsets
    static func make(top: CGFloat) -> UIEdgeInsets {
        return UIEdgeInsets(top: top, left: 0, bottom: 0, right: 0)
    }

    /// 设置left值返回NSUIEdgeInsets
    static func make(left: CGFloat) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: left, bottom: 0, right: 0)
    }

    /// 设置bottom值返回NSUIEdgeInsets
    static func make(bottom: CGFloat) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 0, bottom: bottom, right: 0)
    }

    /// 设置right值返回NSUIEdgeInsets
    static func make(right: CGFloat) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: right)
    }

    /// 判断NSUIEdgeInsets是否相同
    func equalTo(_ insets2: UIEdgeInsets) -> Bool {
        return self == insets2
    }
}
